package cn.hd01.weixin.service;

import cn.hd01.repository.entity.Order;
import cn.hd01.repository.entity.WXApp;
import cn.hd01.repository.entity.WXOauth;
import cn.hd01.util.HttpClientHelper;
import cn.hd01.weixin.model.WxPaySendData;
import cn.hd01.weixin.util.WeiXinUtils;
import com.google.common.collect.Maps;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import org.hibernate.service.spi.ServiceException;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import sun.misc.BASE64Encoder;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

/**
 * @author cyb
 * @date 2017/4/26.
 */
@Service
public class WeixinPayService {

    /**
     * 微信支付统一下单
     */
    public Map<String, Object> unifiedOrder(WXApp wxApp, String notifyUrl, Order order, Map<String, Object> map) {
        Map<String, Object> resultMap;
        try {
            WxPaySendData paySendData = new WxPaySendData();
            //构建微信支付请求参数集合
            paySendData.setAppId(wxApp.getAppId());
            paySendData.setAttach("微信订单支付:" + order.getOrderId());
            paySendData.setBody((String) map.get("body"));
            paySendData.setMchId(wxApp.getMchId());
            paySendData.setNonceStr(WeiXinUtils.nonceStr());
            paySendData.setNotifyUrl(notifyUrl);
            paySendData.setDeviceInfo("WEB");
            paySendData.setOutTradeNo(order.getOrderId());
            paySendData.setTotalFee(order.getSumFee());
            paySendData.setProductId(order.getProductId());
            paySendData.setTradeType((String) map.get("tradeType"));
            paySendData.setSpBillCreateIp((String) map.get("remoteIp"));
            paySendData.setOpenId((String) map.get("openId"));
            //将参数拼成map,生产签名
            Map<String, Object> params = buildParamMap(paySendData);
            paySendData.setSign(WeiXinUtils.getSign(params, wxApp.getShKey()));
            //将请求参数对象转换成xml
            String reqXml = WeiXinUtils.sendDataToXml(paySendData);

            InputStream dataStream = HttpClientHelper.instance().postXml(WeiXinUtils.UNIFIED_ORDER_URL, reqXml);
            resultMap = WeiXinUtils.parseXml(dataStream);
        } catch (Exception e) {
            throw new ServiceException("微信支付统一下单异常", e);
        }
        return resultMap;
    }

    /**
     * 构建统一下单参数map 用于生成签名
     *
     * @param data
     * @return SortedMap<String,Object>
     */
    private Map<String, Object> buildParamMap(WxPaySendData data) {
        Map<String, Object> paramters = new HashMap<String, Object>();
        if (null != data) {
            if (!StringUtils.isEmpty(data.getAppId())) {
                paramters.put("appid", data.getAppId());
            }
            if (!StringUtils.isEmpty(data.getAttach())) {
                paramters.put("attach", data.getAttach());
            }
            if (!StringUtils.isEmpty(data.getBody())) {
                paramters.put("body", data.getBody());
            }
            if (!StringUtils.isEmpty(data.getDetail())) {
                paramters.put("detail", data.getDetail());
            }
            if (!StringUtils.isEmpty(data.getDeviceInfo())) {
                paramters.put("device_info", data.getDeviceInfo());
            }
            if (!StringUtils.isEmpty(data.getFeeType())) {
                paramters.put("fee_type", data.getFeeType());
            }
            if (!StringUtils.isEmpty(data.getGoodsTag())) {
                paramters.put("goods_tag", data.getGoodsTag());
            }
            if (!StringUtils.isEmpty(data.getLimitPay())) {
                paramters.put("limit_pay", data.getLimitPay());
            }
            if (!StringUtils.isEmpty(data.getMchId())) {
                paramters.put("mch_id", data.getMchId());
            }
            if (!StringUtils.isEmpty(data.getNonceStr())) {
                paramters.put("nonce_str", data.getNonceStr());
            }
            if (!StringUtils.isEmpty(data.getNotifyUrl())) {
                paramters.put("notify_url", data.getNotifyUrl());
            }
            if (!StringUtils.isEmpty(data.getOpenId())) {
                paramters.put("openid", data.getOpenId());
            }
            if (!StringUtils.isEmpty(data.getOutTradeNo())) {
                paramters.put("out_trade_no", data.getOutTradeNo());
            }
            if (!StringUtils.isEmpty(data.getSign())) {
                paramters.put("sign", data.getSign());
            }
            if (!StringUtils.isEmpty(data.getSpBillCreateIp())) {
                paramters.put("spbill_create_ip", data.getSpBillCreateIp());
            }
            if (!StringUtils.isEmpty(data.getTimeStart())) {
                paramters.put("time_start", data.getTimeStart());
            }
            if (!StringUtils.isEmpty(data.getTimeExpire())) {
                paramters.put("time_expire", data.getTimeExpire());
            }
            if (!StringUtils.isEmpty(data.getProductId())) {
                paramters.put("product_id", data.getProductId());
            }
            if (data.getTotalFee() > 0) {
                paramters.put("total_fee", data.getTotalFee());
            }
            if (!StringUtils.isEmpty(data.getTradeType())) {
                paramters.put("trade_type", data.getTradeType());
            }
            //申请退款参数
            if (!StringUtils.isEmpty(data.getTransactionId())) {
                paramters.put("transaction_id", data.getTransactionId());
            }
            if (!StringUtils.isEmpty(data.getOutRefundNo())) {
                paramters.put("out_refund_no", data.getOutRefundNo());
            }
            if (!StringUtils.isEmpty(data.getOpUserId())) {
                paramters.put("op_user_id", data.getOpUserId());
            }
            if (!StringUtils.isEmpty(data.getRefundFeeType())) {
                paramters.put("refund_fee_type", data.getRefundFeeType());
            }
            if (null != data.getRefundFee() && data.getRefundFee() > 0) {
                paramters.put("refund_fee", data.getRefundFee());
            }
        }
        return paramters;
    }

    /**
     * 根据二维码链接code_url生成二维码
     */
    public String generateQrcodeToBase64(String codeurl) {
        ByteArrayOutputStream out = null;
        try {
            // 生成二维码核心类
            MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
            Map<EncodeHintType, String> hints = Maps.newHashMap();
            hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); //设置字符集编码类型
            BitMatrix bitMatrix = multiFormatWriter.encode(codeurl, BarcodeFormat.QR_CODE, 300, 300, hints);

            // 将二维码输出到流上面
            out = new ByteArrayOutputStream();
            MatrixToImageWriter.writeToStream(bitMatrix, "png", out);

            return new BASE64Encoder().encode(out.toByteArray());
        } catch (Exception e1) {
            e1.printStackTrace();
            return null;
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 企业向个人支付转账
     */
    public Map<String, Object> transferPay(WXApp wxApp, WXOauth oauth, Order order, String ip) {
        Map<String, Object> resultMap = null;
        try {
            Map<String, Object> paramMap = new HashMap<>();
            paramMap.put("mch_appid", wxApp.getAppId()); //公众账号appid
            paramMap.put("mchid", wxApp.getMchId()); //商户号
            paramMap.put("nonce_str", WeiXinUtils.nonceStr()); //随机字符串
            paramMap.put("partner_trade_no", order.getOrderId()); //商户订单号，暂时直接生成
            paramMap.put("openid", oauth.getOpenId()); //用户openid
            paramMap.put("check_name", "NO_CHECK"); //校验用户姓名选项 OPTION_CHECK
            //parm.put("re_user_name", ""); //check_name设置为FORCE_CHECK或OPTION_CHECK，则必填
            paramMap.put("amount", order.getSumFee()); //转账金额
            paramMap.put("desc", "要点科技转账"); //企业付款描述信息
            paramMap.put("spbill_create_ip", ip); //Ip地址
            paramMap.put("sign", WeiXinUtils.getSign(paramMap, wxApp.getShKey()));

            InputStream dataStream = HttpClientHelper.instance().posts(WeiXinUtils.TRANSFERS_PAY, WeiXinUtils.sendDataToXml(paramMap, false));
            resultMap = WeiXinUtils.parseXml(dataStream);
        } catch (Exception e) {
            throw new ServiceException("微信企业向个人支付失败", e);
        }

        return resultMap;
    }
//
//    public static void main(String[] args) {
//        System.out.println(new WeixinPayService().generateQrcodeToBase64("http://www.baidu.com"));
//    }
}
